package com.example.demo.Controller.UploadFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.Config.FileConfig.WebMvcConfig;
import com.example.demo.Entity.UserInfo.Userinfo;
import com.example.demo.ServiceImpl.UploadFile.UploadfileServiceImpl;
import com.example.demo.Entity.UploadFile.Uploadfile;
import com.example.demo.ServiceImpl.User.UserServiceImpl;
import com.example.demo.ServiceImpl.UserInfo.UserinfoServiceImpl;
import com.example.demo.Utils.JWTUtils.JWTUtils;
import com.example.demo.Utils.RedisUtils.RedisUtil;
import com.example.demo.Utils.Result.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/uploadfile")
@CrossOrigin(origins = "*")
@Tag(name = "UploadfileController", description = "UploadfileController 相关接口")
public class UploadfileController {

    @Resource
    private UploadfileServiceImpl uploadfileService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserinfoServiceImpl userinfoService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @PostMapping
    @Operation(summary = "保存或更新 Uploadfile 信息", description = "根据传入的 Uploadfile 对象保存或更新信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "保存或更新成功", content = @Content(schema = @Schema(implementation = Boolean.class)))
    })
    public Boolean save(@RequestBody Uploadfile uploadfile) {
// 保存或更新数据后，删除相关缓存
        redisUtil.deleteKeysStartingWith("uploadfile");
        return uploadfileService.saveOrUpdate(uploadfile);
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "根据 ID 删除 Uploadfile 信息", description = "根据传入的 ID 删除对应的 Uploadfile 信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "删除成功", content = @Content(schema = @Schema(implementation = Boolean.class)))
    })
    public Boolean delete(@PathVariable(value = "id") Integer id) {
// 删除数据后，删除相关缓存
        redisTemplate.delete("uploadfile:all");
        redisTemplate.delete("uploadfile:id:" + id);
        return uploadfileService.removeById(id);
    }

    @GetMapping
    @Operation(summary = "获取所有 Uploadfile 信息", description = "获取所有 Uploadfile 的列表信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "获取成功", content = @Content(schema = @Schema(implementation = R.class)))
    })
    public R findAll() {
        String key = "uploadfile:all";
        @SuppressWarnings("unchecked")
        List<Uploadfile> uploadfileList = (List<Uploadfile>) redisTemplate.opsForValue().get(key);
        if (uploadfileList == null) {
            uploadfileList = uploadfileService.list();
            redisTemplate.opsForValue().set(key, uploadfileList, 60, TimeUnit.MINUTES);
        }
        return R.ok().put("uploadfileList", uploadfileList);
    }

    @GetMapping("/{id}")
    @Operation(summary = "根据 ID 获取 Uploadfile 信息", description = "根据传入的 ID 获取对应的 Uploadfile 信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "获取成功", content = @Content(schema = @Schema(implementation = R.class)))
    })
    public R findOne(@PathVariable(value = "id") Integer id) {
        String key = "uploadfile:id:" + id;
        Uploadfile uploadfile = (Uploadfile) redisTemplate.opsForValue().get(key);
        if (uploadfile == null) {
            uploadfile = uploadfileService.getById(id);
            if (uploadfile != null) {
                redisTemplate.opsForValue().set(key, uploadfile, 60, TimeUnit.MINUTES);
            }
        }
        return R.ok().put("uploadfile", uploadfile);
    }

    @GetMapping("/page")
    @Operation(summary = "分页获取 Uploadfile 信息", description = "根据传入的页码和每页数量分页获取 Uploadfile 信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "获取成功", content = @Content(schema = @Schema(implementation = R.class)))
    })
    @Parameter(name = "pageNum", in = ParameterIn.QUERY, description = "页码", required = true)
    @Parameter(name = "pageSize", in = ParameterIn.QUERY, description = "每页数量", required = true)
    @Parameter(name = "keyword", in = ParameterIn.QUERY, description = "搜索关键字", required = false)
    public R findPage(@RequestParam(value = "pageNum") Integer pageNum,
                      @RequestParam(value = "pageSize") Integer pageSize,
                      @RequestParam(value = "keyword", required = false) String keyword) {
        String key = "uploadfile:page:" + pageNum + ":" + pageSize + ":keyword:" + keyword;
        @SuppressWarnings("unchecked")
        Page<Uploadfile> uploadfilePage = (Page<Uploadfile>) redisTemplate.opsForValue().get(key);
        if (uploadfilePage == null) {
            LambdaQueryWrapper<Uploadfile> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.orderByDesc(Uploadfile::getFileId);
            if (keyword != null) {
                LambdaQueryWrapper<Userinfo> userinfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userinfoLambdaQueryWrapper.like(Userinfo::getNickname, keyword);
                List<Userinfo> userinfoList = userinfoService.list(userinfoLambdaQueryWrapper);
                List<Integer> userIds = new ArrayList<>();
                for (Userinfo userinfo : userinfoList) {
                    userIds.add(userinfo.getUserId());
                }
                queryWrapper.like(Uploadfile::getFileName, keyword);
                if (!userIds.isEmpty()) {
                    queryWrapper.or()
                            .like(Uploadfile::getFileType, keyword).or().in(Uploadfile::getUploadUserId, userIds);
                }
            }
            uploadfilePage = uploadfileService.page(new Page<>(pageNum, pageSize), queryWrapper);
            redisTemplate.opsForValue().set(key, uploadfilePage, 60, TimeUnit.MINUTES);
        }
        return R.ok().put("uploadfilePage", uploadfilePage);
    }

    @PostMapping("/upload")
    @Operation(summary = "上传文件", description = "上传文件")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "上传成功", content = @Content(schema = @Schema(implementation = R.class)))
    })
    public R upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        try {
            String token = request.getHeader("Authorization");
            Integer userId = Integer.valueOf(JWTUtils.getUserIDFromToken(token));
            String fileName = file.getOriginalFilename();
            if (fileName != null) {
                fileName = UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));
            }
            String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
            file.transferTo(new File(WebMvcConfig.LocalPath + fileName));
            String webUrl = WebMvcConfig.WebMvcPath + fileName;
            Uploadfile uploadfile = new Uploadfile();
            uploadfile.setFileUrl(webUrl);
            uploadfile.setFileType(fileType);
            uploadfile.setFileName(fileName);
            uploadfile.setUploadUserId(userId);
            uploadfile.setUploadTime(new Date());
            uploadfileService.save(uploadfile);
            return R.ok().put("fileName", fileName).put("fileType", fileType).put("url", webUrl);
        } catch (Exception e) {
            return R.error("上传失败");
        }
    }
}